; ******************************************************************************

;

;  LiniStepper v2

;  PIC 16F84 / 16F628 / 16F628A code (updated 628A June 2007)

;  Copyright Aug 2002 - Nov 2009 - Roman Black   http://www.romanblack.com

;

;  PIC assembler code for the LiniStepper stepper motor driver board.

;  200/400/1200/3600 steps

;

;  v2.0	New version 2.0; 2nd Nov 2009.

;		* modified v1 source to work with new Lini v2 PCB.

;		* STEP and DIR are the same, but POWER is now "ENABLE" (active LOW)

;		  (so the POWER pin function is inverted in Lini v2) 

;  v2.1   Updated 16th Nov 2010.

;		Now incorporates update suggested by Brian D Freeman; improves

;         performance by skipping the current calculation on the hi-lo

;         transition of the step input.

;

;  (set mplab TABS to 5 for best viewing this .asm file)

;******************************************************************************





;==============================================================================

; mplab settings



	ERRORLEVEL -224		; suppress annoying message because of option/tris

	ERRORLEVEL -302		; suppress message because of bank select in setup ports



	LIST b=5, n=97, t=ON, st=OFF		;

	; absolute listing tabs=5, lines=97, trim long lines=ON, symbol table=OFF



;==============================================================================

; processor defined



	;include <p16f84A.inc>

	include <p16f628.inc>

	;include <p16f628A.inc>



; processor config



	IFDEF __16F84A

		__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC

	ENDIF

	IFDEF __16F628

		__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF

	ENDIF

	IFDEF __16F628A

		__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF

	ENDIF





;==============================================================================

; Variables here



	;-------------------------------------------------

	IFDEF __16F84A

		#define RAM_START	0x0C

		#define RAM_END	RAM_START+d'68' 		; 16F84 has only 68 ram

	ENDIF

	IFDEF __16F628

		#define RAM_START	0x20	

		#define RAM_END	RAM_START+d'96' 		; F628 has 96 ram

	ENDIF

	IFDEF __16F628A

		#define RAM_START	0x20	

		#define RAM_END	RAM_START+d'96' 		; F628A has 96 ram

	ENDIF

	;-------------------------------------------------

	CBLOCK 	RAM_START



		status_temp		; used for int servicing

		w_temp			; used for int servicing



		step				; (0-71) ustep position!

		steptemp			; for calcs



		phase			; stores the 4 motor phase pins 0000xxxx

		current1			; for current tween pwm

		current2			; for current tween pwm



		inputs			; stores new input pins

		inputs_last		; stores last states of input pins



	ENDC



	;-------------------------------------------------

	; PIC input pins for porta



	#define 	STEP			0		; / = move 1 step, \=do nothing

	#define 	DIR			1		; lo= cw,  hi=ccw

	#define 	POWER		2		; lo=full power, hi=half power

			; (Note! POWER pin was inverted for v2 !!!)

	;-------------------------------------------------

	; Custom instructions!



	#define	skpwne		skpnz			; after subxx, uses zero

	#define	skpweq		skpz				; after subxx, uses zero

	#define	skpwle		skpc				; after subxx, uses carry

	#define	skpwgt		skpnc			; after subxx, uses carry



;==============================================================================

; CODE GOES HERE



	org 0x0000 			; Set program memory base at reset vector 0x00

reset

	goto main				;







;==============================================================================

; INTERRUPT vector here

	org 0x0004 			; interrupt routine must start here

int_routine



	;-------------------------------------------------

						; first we preserve w and status register



	movwf w_temp      		; save off current W register contents

	movf	STATUS,w          	; move status register into W register

	movwf status_temp       	; save off contents of STATUS register

	;-------------------------------------------------

						; we get here every 256 timer0 ticks  3900Hz

						; int body code here if you want



	;-------------------------------------------------

						; finally we restore w and status registers and

						; clear TMRO int flag now we are finished.

int_exit

	bcf INTCON,T0IF		; reset the tmr0 interrupt flag

	movf status_temp,w     	; retrieve copy of STATUS register

	movwf STATUS            	; restore pre-isr STATUS register contents

	swapf w_temp,f

	swapf w_temp,w          	; restore pre-isr W register contents

	retfie				; return from interrupt

	;-------------------------------------------------



;==============================================================================









;******************************************************************************

; MOVE MOTOR  		  sets 8 portb output pins to control motor

;******************************************************************************

; NOTE!! var step is used for sequencing the 0-71 steps

; uses tables! so keep it first in the code and set PCLATH to page 0



;------------------

move_motor				; goto label

;------------------



	;-------------------------------------------------

	; this code controls the phase sequencing and current

	; settings for the motor.



	; there are always 72 steps (0-71)



	; we can split the main table into 2 halves, each have identical

	; current sequencing. That is only 12 entries for hardware current.



	; Then can x3 the table to get 36 table entries which cover all 72 steps.

	; the 36 entries jump to 36 code pieces, which set the current values

	; for the 2 possible tween steps... We need 2 current values, one

	; for the x2 value and one for the x1 value.

	;-------------------------------------------------

	; PHASE SEQUENCING (switch the 4 coils)



	; there are 4 possible combinations for the phase switching:

	; each have 18 steps, total 72 steps:



	;	A+ B+	range 0		step 0-17

	;	A- B+	range 1		18-35

	;	A- B-	range 2		36-53

	;	A+ B-	range 3		54-71



	;-------------------------------------------------

						; find which of the 4 ranges we are in

	movf step,w			; get step

	movwf steptemp			; store as working temp



	movf steptemp,w		;

	sublw d'35'			; sub to test

	skpwle				;

	goto half_hi			; wgt, steptemp is 36-71 (upper half)



	;-------------------------

half_low					; wle, steptemp is 0-35



	movf steptemp,w		;

	sublw d'17'			; sub to test

	skpwle				;

	goto range1			; wgt

	

range0					; wle

	movlw b'00000101'		; 0101 = A+ B+

	goto phase_done		;



range1

	movlw b'00001001'		; 1001 = A- B+

	goto phase_done		;



	;-------------------------

half_hi					; steptemp is 36-71

						; NOTE! must subtract 36 from steptemp, so it

						; will become 0-35 and ok with table later!

	movlw d'36'			; subtract 36 from steptemp,

	subwf steptemp,f		; (now steptemp is 0-35)



						; now find the range

	movf steptemp,w		;

	sublw d'17'			; sub to test

	skpwle				;

	goto range3			; wgt

	

range2					; wle

	movlw b'00001010'		; 1010 = A- B-

	goto phase_done		;



range3

	movlw b'00000110'		; 0110 = A+ B-



phase_done				; note! steptemp is always 0-35 by here

	movwf phase			; store phase values



	;-------------------------------------------------

	; at this point we have the phasing done and stored as the last

	; 4 bits in var phase; 0000xxxx

	

	; now we have 36 possible current combinations, which we can do

	; by separate code fragments, from a jump table.



	; as we have 2 power modes; full and low power, we

	; need 2 tables.



	;-------------------------------------------------



	btfsc inputs,POWER		; select table to use

	goto table_lowpower		;



	;-------------------------------------------------

	; HIGH POWER TABLE

	;-------------------------------------------------



table_highpower			;



	movf steptemp,w		; add steptemp to the PCL

	addwf PCL,f			; 

						; here are the 36 possible values;

	;-------------------------

	goto st00				; * (hardware 6th steps)

	goto st01				;   (pwm tween steps)

	goto st02				;   (pwm tween steps)

	goto st03				; *

	goto st04				; 

	goto st05				; 



	goto st06				; *

	goto st07				;

	goto st08				;

	goto st09				; *

	goto st10				;

	goto st11				;



	goto st12				; *

	goto st13				;

	goto st14				;

	goto st15				; *

	goto st16				;

	goto st17				;



	goto st18				; *

	goto st19				;

	goto st20				;

	goto st21				; *

	goto st22				;

	goto st23				;



	goto st24				; *

	goto st25				;

	goto st26				;

	goto st27				; *

	goto st28				;

	goto st29				;



	goto st30				; *

	goto st31				;

	goto st32				;

	goto st33				; *

	goto st34				;

	goto st35				;



	;-------------------------------------------------

	; LOW POWER TABLE

	;-------------------------------------------------

	; as low power mode is for wait periods we don't need to

	; maintain the full step precision and can wait on the

	; half-step (400 steps/rev). This means much easier code tables.

	; The nature of the board electronics is not really suited

	; for LOW power microstepping, but it could be programmed here

	; if needed.



	; NOTE!! uses my hi-torque half stepping, not normal half step.



	;  doing half stepping with the 55,25 current values gives;

	; 55+25 = 80

	; max current 100+100 = 200

	; typical (high) current 100+50 = 150

	; so low power is about 1/2 the current of high power mode,

	; giving about 1/4 the motor heating and half the driver heating.



	; for now it uses only half-steps or 8 separate current modes.

	; we only have to use 4 actual current modes as

	; the table is doubled like the table_highpower is.



	; NOTE!! I have left the table full sized so it can be modified

	; to 1200 or 3600 steps if needed.

	;-------------------------------------------------



table_lowpower				;



	movf steptemp,w		; add steptemp to the PCL

	addwf PCL,f			; 

						; here are the 36 possible values;

	;-------------------------

						; A+ B+ (A- B-)



	goto lp00				;

	goto lp00				;

	goto lp00				;

	goto lp00				;

	goto lp00				;	55,25 (100,45) current low (high)

	goto lp00				;

	goto lp00				;

	goto lp00				;

	goto lp00				;



	goto lp09				;

	goto lp09				;

	goto lp09				;

	goto lp09				;

	goto lp09				;	25,55 (45,100)

	goto lp09				;

	goto lp09				;

	goto lp09				;

	goto lp09				;



	;-------------------------

						; A- B+ (A+ B-)



	goto lp18				;

	goto lp18				;

	goto lp18				;

	goto lp18				;

	goto lp18				;	25,55 (45,100)

	goto lp18				;

	goto lp18				;

	goto lp18				;

	goto lp18				;



	goto lp27				;

	goto lp27				;

	goto lp27				;

	goto lp27				;

	goto lp27				;	55,25 (100,45)

	goto lp27				;

	goto lp27				;

	goto lp27				;

	goto lp27				;



	;-------------------------------------------------

	; all tables done, no more tables after this point!

	;-------------------------------------------------

	; next are the 36 code fragments for the high power table.



	; CURRENT INFO.

	; hardware requires that we send the entire 8 bits to the motor

	; at one time, to keep pwm fast.



	; ----xxxx,  where xxxx is the coils on/off phasing (done)

	; xxxx----,  where xxxx is the current settings for the A and B phases;

	; xx------,  where xx is current for A phase

	; --xx----,  where xx is current for B phase



	; hardware currents for 6th stepping have 4 possible values;

	; 00  =  0% current

	; 01  =  25% current

	; 10  =  55% current

	; 11  =  100% current



	;-------------------------------------------------

	; PWM INFO.

	; hardware gives us 6th steps, or 1200 steps/rev.

	; to get 3600 steps/rev we need TWO more

	; "tween" steps between every proper hardware 6th step.



	; to do this we set 2 currents, current1 and current2.

	; then we do FAST pwm, with 2 time units at current2,

	; and 1 time unit at current1.

	; this gives a current which is between the two currents,

	; proportionally closer to current2. (2/3 obviously)

	; this gives the ability to get 2 evenly spaced "tween" currents

	; between our hardware 6th step currents, and go from 1200 to 3600.



	; the next 36 code fragments set the 2 currents desired, then

	; we goto a fast-pwm loop (same loop used for all currents)

	; which modulates between the 2 currents and gives final

	; output current.

	;-------------------------------------------------



st00						; (6th step)

	movf phase,w			; get coil phasing (is 0000xxxx)

	iorlw b'11000000'		; set currents; 100,0 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st01						; (tween step)

	movf phase,w			; get coil phasing

	iorlw b'11000000'		; set 100,0 

	movwf current2			;

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current1			;

	goto pwm				;



st02						; (tween step)

	movf phase,w			; get coil phasing

	iorlw b'11010000'		; set 100,25 

	movwf current2			;

	movf phase,w			;

	iorlw b'11000000'		; set 100,0 

	movwf current1			;

	goto pwm				;



	;-------------------------



st03						; (6th step)

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st04						;

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current2			;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current1			;

	goto pwm				;



st05						;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current2			;

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current1			;

	goto pwm				;



	;-------------------------



st06						; (6th step)

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st07						;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current2			;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current1			;

	goto pwm				;



st08						;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100

	movwf current2			;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current1			;

	goto pwm				;



	;-------------------------



st09						; (6th step)

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st10						;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current2			;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current1			;

	goto pwm				;



st11						;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100

	movwf current2			;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current1			;

	goto pwm				;



	;-------------------------



st12						; (6th step)

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st13						;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current2			;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current1			;

	goto pwm				;



st14						;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100

	movwf current2			;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current1			;

	goto pwm				;



	;-------------------------

st15						; (6th step)

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st16						;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current2			;

	movf phase,w			;

	iorlw b'00110000'		; set 0,100 

	movwf current1			;

	goto pwm				;



st17						;

	movf phase,w			;

	iorlw b'00110000'		; set 0,100

	movwf current2			;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current1			;

	goto pwm				;



	;-------------------------

	;-------------------------



st18						; (6th step)

	movf phase,w			;

	iorlw b'00110000'		; set 0,100 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st19						;

	movf phase,w			;

	iorlw b'00110000'		; set 0,100 

	movwf current2			;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current1			;

	goto pwm				;



st20						;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100

	movwf current2			;

	movf phase,w			;

	iorlw b'00110000'		; set 0,100 

	movwf current1			;

	goto pwm				;



	;-------------------------



st21						; (6th step)

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st22						;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current2			;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current1			;

	goto pwm				;



st23						;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100

	movwf current2			;

	movf phase,w			;

	iorlw b'01110000'		; set 25,100 

	movwf current1			;

	goto pwm				;



	;-------------------------



st24						; (6th step)

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st25						;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current2			;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current1			;

	goto pwm				;



st26						;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100

	movwf current2			;

	movf phase,w			;

	iorlw b'10110000'		; set 55,100 

	movwf current1			;

	goto pwm				;



	;-------------------------



st27						; (6th step)

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st28						;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current2			;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current1			;

	goto pwm				;



st29						;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55

	movwf current2			;

	movf phase,w			;

	iorlw b'11110000'		; set 100,100 

	movwf current1			;

	goto pwm				;



	;-------------------------



st30						; (6th step)

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st31						;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current2			;

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current1			;

	goto pwm				;



st32						;

	movf phase,w			;

	iorlw b'11010000'		; set 100,25

	movwf current2			;

	movf phase,w			;

	iorlw b'11100000'		; set 100,55 

	movwf current1			;

	goto pwm				;



	;-------------------------



st33						; (6th step)

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current2			;

	movwf current1			;

	goto pwm				;



st34						;

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current2			;

	movf phase,w			;

	iorlw b'11000000'		; set 100,0 

	movwf current1			;

	goto pwm				;



st35						;

	movf phase,w			;

	iorlw b'11000000'		; set 100,0

	movwf current2			;

	movf phase,w			;

	iorlw b'11010000'		; set 100,25 

	movwf current1			;

	goto pwm				;

						; high power table done!





	;-------------------------------------------------

	; next are the 4 code fragments for the low power table.

	; (no PWM is used)

	;-------------------------------------------------



lp00						;

	movf phase,w			;

	iorlw b'10010000'		; set 55,25 

	movwf current2			;

	movwf current1			;

	goto pwm				;



lp09						;

	movf phase,w			;

	iorlw b'01100000'		; set 25,55 

	movwf current2			;

	movwf current1			;

	goto pwm				;



lp18						;

	movf phase,w			;

	iorlw b'01100000'		; set 25,55 

	movwf current2			;

	movwf current1			;

	goto pwm				;



lp27						;

	movf phase,w			;

	iorlw b'10010000'		; set 55,25

	movwf current2			;

	movwf current1			;

	goto pwm				;



	;-------------------------------------------------





;------------------------------------------------------------------------------









;******************************************************************************

;  Main 

;******************************************************************************

;

;------------------

main						; goto label

;------------------



	;---------------------------------------------

						; do initial setup for ports and ints and stuff

	call setup			; this is our only proper call...

						; it is called only once, and does not really need

						; to be a function.

	;---------------------------------------------

	; main operating loop is here.

	;---------------------------------------------



	goto move_motor		; will set the motor to step 0,

						; and loop permanently from there



	;---------------------------------------------

	goto main				; safe loop, should never get here anyway.



;==============================================================================









;******************************************************************************

; NEW INPUTS   input change was detected

;******************************************************************************

;

;------------------

new_inputs				; goto tag

;------------------



	;-------------------------------------------------

	; when we enter here:

	; * one or more PORTA inputs have just changed

	; * inputs_last	contains last PORTA inputs values

	; * inputs		contains new PORTA inputs values

	;-------------------------------------------------

	; must first detect which input pins changed.



	; ---x----	RA4	* mode bit1	   ( 00=200 step	01=400 step

	; ----x---	RA3	* mode bit0		10=1200 step	11=3600 step )

	; -----x--	RA2	* power  (Lini v2; now 0 = full power!)

	; ------x-	RA1	* direction

	; -------x	RA0	* step



	; if step went hi, we move the step (step++ or step--)



	; if step went low, ignore

	; ignore change in direction pin

	; ignore change in power pin

	; ignore change in mode pins

	; (all pins besides step are handled automatically in move_motor)

	;-------------------------------------------------



	movf inputs,w			; xor to compare new inputs with last values

	xorwf inputs_last,f		; now inputs_last has the diff.



	btfss inputs_last,STEP	; test if step input changed

	goto ni_end			; 



						; step input changed!

	btfsc inputs,STEP		; test if change was lo-hi or hi-lo

	goto trans_hi			; lo-hi, so process a step!



						; hi-lo, so ignore this transition

	bcf inputs_last,STEP	; record new state of step pin

	goto pwm				; fast exit back to pwm()



	;-------------------------------------------------

	; step input changed lo-hi!

	; now must make a step forward or back, based

	; on the state of the dir pin.



	; here it gets complex as we have 4 operating modes,

	; determined by the state of the 2 input pins RA4 and RA3;



	; ---00---	200 steps

	; ---01---	400 steps

	; ---10---	1200 steps

	; ---11---	3600 steps



	; there are 4 separate code systems to handle stepping 

	; in the 4 modes;

	;-------------------------------------------------

trans_hi

						; find which of the 4 modes we are in

	btfss inputs,4			; test hi bit

	goto mode_lo			;



mode_hi					; must be 1200 or 3600



	btfss inputs,3			; test lo bit

	goto mode_1200			;



	;-------------------------------------------------

mode_3600					; 3600 mode (72/1)

						; each step is 1



	btfss inputs,DIR		; test direction input

	goto m36_up			;



m36_down

	decf step,f			; step--

	btfss step,7			; test for roll under <0

	goto ni_end			; ok

						; rolled under!

	movlw d'71'			; force to top step (72-1)

	movwf step			;

	goto ni_end			;



m36_up

	incf step,f			; step++

	movf step,w			; test for roll over >71

	sublw d'71'			; sub to test

	skpwle				;

	clrf step				; wgt, rolled over so force to step 0



	goto ni_end			;

	;-------------------------------------------------

mode_1200					; 1200 mode (72/3)

						; each step is mod 3 (0,3,6,9,12 - 66, 69 etc)



	btfss inputs,DIR		; test direction input

	goto m12_up			;



m12_down

	movlw d'3'			; amount to subtract

	subwf step,f			; step-=3

	btfss step,7			; test for roll under <0

	goto ni_end			; ok

						; rolled under!

	movlw d'69'			; force to top step (72-3)

	movwf step			;

	goto ni_end			;



m12_up

	movlw d'3'			; amount to add

	addwf step,f			; step+=3

						;

	movf step,w			; test for roll over >69

	sublw d'69'			; sub to test

	skpwle				;

	clrf step				; wgt, rolled over so force to step 0



	goto ni_end			;

	;-------------------------------------------------

mode_lo					; must be 200 or 400

	btfss inputs,3			; test lo bit

	goto mode_200			;



	;-------------------------------------------------

mode_400					; 400 mode (72/9)

						; note! we do special half stepping here.

						; there are ONLY 8 valid steps:

						; 4, 13, 22, 31, 40, 49, 58, 67

						; these steps give 100,45 and 35,100 combos, good

						; enough for now. (should average 100,41)



	btfss inputs,DIR		; test direction input

	goto m4_up			;



m4_down

	movlw d'9'			; amount to subtract

	subwf step,f			; step-=9

	btfss step,7			; test for roll under <0

	goto ni_end			; ok

						; rolled under!

	movlw d'67'			; force to top (full) step 

	movwf step			;

	goto ni_end			;



m4_up

	movlw d'9'			; amount to add

	addwf step,f			; step+=9

						;

	movf step,w			; test for roll over

	sublw d'67'			; sub to test

	skpwgt				;

	goto ni_end			; wle, is ok



	movlw d'4'			; wgt, rolled over so force to bottom step 5

	movwf step			;



	goto ni_end			;

	;-------------------------------------------------

mode_200					; 200 mode (72/18)

						; NOTE!! this has special needs as we can't use

						; step 0, we need to stay on the "2 steps on" steps.

						; there are ONLY 4 valid steps;  9, 27, 45, 63



	btfss inputs,DIR		; test direction input

	goto m2_up			;



m2_down

	movlw d'18'			; amount to subtract

	subwf step,f			; step-=18

	btfss step,7			; test for roll under <0

	goto ni_end			; ok

						; rolled under!

	movlw d'63'			; force to top (full) step (72-(18/2))

	movwf step			;

	goto ni_end			;



m2_up

	movlw d'18'			; amount to add

	addwf step,f			; step+=18

						;

	movf step,w			; test for roll over

	sublw d'63'			; sub to test

	skpwgt				;

	goto ni_end			; wle, is ok



	movlw d'9'			; wgt, rolled over so force to bottom step 9

	movwf step			;



	goto ni_end			;



	;-------------------------------------------------

ni_end

	movf inputs,w			; save a copy of the inputs

	movwf inputs_last		;



	goto move_motor		; go and make it all happen



;------------------------------------------------------------------------------









;******************************************************************************

; PWM		is the fast pwm loop

;******************************************************************************

; NOTE!! we enter the code in the middle of the loop!



	;-------------------------------------------------

	; the 2 target currents were set in the move_motor code.



	; what this function does is spend 2 time units at current2,

	; and 1 time unit at current1.

	; actual is 8 clocks at current2

	; and 4 clocks at current 1

	; total 12 cycles, so 333 kHz with 16MHz resonator.



	; this gives an average pwm current of 2/3 the way between

	; current2 and current1.



	; the routine is kept short to keep pwm frequency high, so it

	; is easy to smooth in hardware by the ramping caps.



	; IMPORTANT! is timed by clock cycles, don't change this code!

	; it also checks for any change in input pins here



	; the 8/4 code seen here was supplied by Eric Bohlman (thanks!)

	;-------------------------------------------------

pwm_loop

						; first output current1 to motor

	movf current1,w		; get currents and phase switching

	movwf PORTB			; send to motor!



	nop					; timing delay

	nop					;

						; (4 cycles)

	;-------------------------

pwm						; main entry!

						; better to enter at current2 for motor power.



						; now output current2

	movf current2,w		;

	movwf PORTB			; send to motor!

	nop					; safe wait 250nS



						; now test input pins

	movf PORTA,w			; get pin values from port



	xorwf inputs_last,w		; xor to compare new inputs with last values

	skpnz

	goto pwm_loop			; z, inputs not changed, so keep looping

						; (8 cycles)

	;-------------------------------------------------

						; nz, one or more input pins have changed!

	xorwf inputs_last,w		; restore xored value back to the orig inputs value

	movwf inputs			;



	goto new_inputs		; 

	;-------------------------------------------------



;------------------------------------------------------------------------------













;******************************************************************************

;  SETUP   sets port directions and interrupt stuff etc,

;******************************************************************************

; NOTE!! is the only proper funtion, is done before other activity



;------------------

setup					; routine tag

;------------------



	;-------------------------------------------------

	; Note! there are added bits for the 16F628!

	; here we set up peripherals and port directions.

	; this will need to be changed for different PICs.

	;-------------------------------------------------

						; OPTION setup

	movlw b'10000010'		;

		;  x-------		; 7, 0=enable, 1=disable, portb pullups

		;  -x------		; 6, 1=/, int edge select bit

		;  --x-----		; 5, timer0 source, 0=internal clock, 1=ext pin.

		;  ---x----		; 4, timer0 ext edge, 1=\

		;  ----x---		; 3, prescaler assign, 1=wdt, 0=timer0

		;  -----x--		; 2,1,0, timer0 prescaler rate select

		;  ------x-		;   000=2, 001=4, 010=8, 011=16, etc.

		;  -------x		; 

						;

	banksel OPTION_REG		; go proper reg bank

	movwf OPTION_REG		; load data into OPTION_REG

	banksel 0				;

	;-------------------------------------------------

	; note! check for 16F628 (and A) and do extra setup for it.



	IFDEF  __16F628

		banksel VRCON		; do bank 1 stuff

		clrf VRCON		; disable Vref

		clrf PIE1			; disable pi etc

		banksel 0			;



		clrf T1CON		; disable timer1

		clrf T2CON		; disable timer2

		clrf CCP1CON		; disable CCP module



		movlw b'00000111'	; disable comparators

		movwf CMCON		;

	ENDIF

	IFDEF  __16F628A

		banksel VRCON		; do bank 1 stuff

		clrf VRCON		; disable Vref

		clrf PIE1			; disable pi etc

		banksel 0			;



		clrf T1CON		; disable timer1

		clrf T2CON		; disable timer2

		clrf CCP1CON		; disable CCP module



		movlw b'00000111'	; disable comparators

		movwf CMCON		;

	ENDIF

	;-------------------------------------------------

						; PORTB pins direction setup

						; 1=input, 0=output

	clrf PORTB			;

						;

	movlw b'00000000'		; all 8 portb are outputs

						;

	banksel TRISB			; go proper reg bank

	movwf TRISB			; send mask to portb

	banksel 0				;

	;-------------------------------------------------



						; PORTA pins direction setup

						; 1=input, 0=output

	clrf PORTA			;



						; NOTE!! all 5 PORTA pins are inputs

	movlw b'00011111'		;

		;  ---x----		; RA4

		;  ----x---		; RA3

		;  -----x--		; RA2

		;  ------x-		; RA1

		;  -------x		; RA0



	banksel TRISA			; go proper reg bank

	movwf TRISA			; send mask to porta

	banksel 0				;

	;-------------------------------------------------



	movlw 0x00			; set up PCLATH for all jump tables on page 0

	movwf PCLATH			; (all tables are in move_motor)

	;-------------------------------------------------



						; CLEAR RAM! for lower bank

	movlw RAM_START		; first byte of ram

	movwf FSR				; load pointer

ram_clear_loop

	clrf INDF				; clear the ram we pointed to

	incf FSR,f			; inc pointer to next ram byte

	movf FSR,w			; get copy of pointer to w

	sublw RAM_END			; test if PAST the last byte now

	skpweq				;

	goto ram_clear_loop		;



	;-------------------------------------------------

						; here we can set the user variables and output pins



	movlw 0x00			; for step 0 of 0-71

	movwf step			; loaded ready for jump table



	movf PORTA,w			; get initial value for inputs

	movwf inputs			;

	movwf inputs_last		;



	;-------------------------------------------------

						; set up INTCON register last

	movlw b'00000000'		; set the bit value 



		;  x-------		; bit7 	GIE global int enable, 1=enabled

		;  -x------		; bit6	EE write complete enable, 1=en

		;  --x-----		; bit5 	TMR0 overflow int enable, 1=en

		;  ---x----		; bit4 	RB0/INT enable, 1=en

		;  ----x---		; bit3	RB port change int enable, 1=en

		;  -----x--		; bit2	TMR0 int flag bit, 1=did overflow and get int

		;  ------x-		; bit1	RB0/INT flag bit, 1=did get int

		;  -------x		; bit0	RB port int flag bit, 1=did get int



	movwf INTCON			; put in INTCON register

	;-------------------------------------------------

	return				;

;------------------------------------------------------------------------------











;==============================================================================

	; this code is only to display 1k of the memory usage chart

	; in the absolute listing!



	; page 0 256 byte block--------------------

	;org 0x40-2

	;nop

	;org 0x80-1

	;nop

	;org 0xC0-1

	;nop

	;org 0x100-1

	;nop



	; page 1 256 byte block--------------------

	;org 0x140-2

	;nop

	;org 0x180-1

	;nop

	;org 0x1C0-1

	;nop

	;org 0x200-1

	;nop



	; page 2 256 byte block--------------------

	org 0x240-2

	nop

	org 0x280-1

	nop

	org 0x2C0-1

	nop

	org 0x300-1

	nop



	; page 3 256 byte block--------------------

	org 0x340-2

	nop

	org 0x380-1

	nop

	org 0x3C0-1

	nop

	org 0x400-1

	nop





	IFDEF __16F628A

		; page 4 256 byte block--------------------

		org 0x440-2

		nop

		org 0x480-1

		nop

		org 0x4C0-1

		nop

		org 0x500-1

		nop



		; page 5 256 byte block--------------------

		org 0x540-2

		nop

		org 0x580-1

		nop

		org 0x5C0-1

		nop

		org 0x600-1

		nop



		; page 6 256 byte block--------------------

		org 0x640-2

		nop

		org 0x680-1

		nop

		org 0x6C0-1

		nop

		org 0x700-1

		nop



		; page 7 256 byte block--------------------

		org 0x740-2

		nop

		org 0x780-1

		nop

		org 0x7C0-1

		nop

		org 0x800-1

		nop

	ENDIF



	;-------------------------------------------------------------------------

	end

	;-------------------------------------------------------------------------



;==============================================================================

;==============================================================================

;==============================================================================
